//
//  SLBlockController.m
//  Objective-C
//
//  Created by S_Line on 2018/8/6.
//  Copyright © 2018年 S_Line. All rights reserved.
//

#import "SLBlockController.h"

typedef void(^EOCCompletionHandler)(NSData *data, NSError *error);

@interface SLBlockController ()

@property (nonatomic, strong) NSNumber *number;

@end

@implementation SLBlockController

- (void)initNavBar {
    self.navTitle = @"Block 块";
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initNavBar];
    
    [self initData];
}

- (void)initData {
    /**
     定义一个不带参数和返回值的block
     */
    void (^someBlock)(void) = ^{
        // Block implementation here
        SLog(@"%@", @"------someBlock------");
    };
    
    someBlock();
    
    /**
     带返回值和参数的block
     */
    int (^addBlock)(int a, int b) = ^(int a, int b){
        return a + b;
    };
    
    int add = addBlock(3, 6);
    SLog(@"------ add: %d ------", add);
    
    [self testSelf];
    
    /**
     * 全局块, 栈块及堆块
     * 定义块的时候, 其所占的内存区域是分配在栈中的. 这就是说, 块只在定义它的那个范围内有效.
     * 以下代码时而正确, 时而错误.
     */
//    void (^ block)(void);
//    int a = 8;
//    int b = 7;
//    if (a > b) {
//        block = ^{
//            SLog(@"Block A");
//        };
//    } else {
//        block = ^{
//            SLog(@"Block B");
//        };
//    }
//    block();
    /**
     * 为了解决此问题, 可给块对象发送copy消息以拷贝之. 这样的话, 就可以把块对象从栈复制到堆了.
     */
    void (^ block)(void);
    int a = 8;
    int b = 7;
    if (a > b) {
        block = [^{
            SLog(@"Block A");
        } copy];
    } else {
        [block = ^{
            SLog(@"Block B");
        } copy];
    }
    block();
    /**
     * 全局块
     * 全局块不会捕捉任何状态(比如外围的变量等), 运行时也无需有状态来参与. 块所使用的整个内存区域在编译期已经完全确定了, 因此, 全局块可以声明在全局内存里, 而不需要在每次用到的时候于栈中创建.
     */
    void (^globalBlock)(void) = ^{
        SLog(@"-------- globalBlock ---------");
    };
    
    globalBlock();
    
    // typedef
    [self startWithCompletionHandler:^(NSData *data, NSError *error) {
        SLog(@"-------- completionHandler: %@ --------", data);
    }];
}

- (void)testSelf {
    // ...
    SLBlockController * __weak weakSelf = self;
    void (^someBlock)(void) = ^ {
        weakSelf.number = @10;
        SLog(@"-------- number: %@ ---------", weakSelf.number);
    };
    
    someBlock();
}

- (void)startWithCompletionHandler:(EOCCompletionHandler)completionHandler {
    NSData *data = [@"abc" dataUsingEncoding:NSUTF8StringEncoding];
    
    completionHandler(data, nil);
}

@end
